<?php
/**
 *    Interrogates the stack trace to recover the
 *    failure point.
 */
class QStone_StackTrace {
    private $prefixes = Array('assert', 'expect', 'pass', 'fail');
    private static $stackTracer = null;

    /**
     *    Stashes the list of target prefixes.
     *    @param array $prefixes      List of method prefixes
     *                                to search for.
     */
    private function __construct() {}
    private function __clone(){}
    public static function getTracer(){
        if(!self::$stackTracer instanceof self){
            self::$stackTracer = new self();
        }
        return self::$stackTracer;
    }

    /**
     *    Extracts the last method name that was not within
     *    QStonetest itself. Captures a stack trace if none given.
     *    @param array $stack      List of stack frames.
     *    @return string           Snippet of test report with line
     *                             number and file.
     */
    function traceMethod($stack = false) {
        $stack = $stack ? $stack : $this->captureTrace();
        foreach ($stack as $frame) {
            if($this->methodBeginWith($frame)){
                return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ' function '.$frame['function'].']';
            }
        }
        return '';
    }

    /**
     *    Tries to determine if the method call is an assert, etc.
     *    @param array $frame     PHP stack frame.
     *    @return boolean         True if matches a target.
     */
    private function methodBeginWith($frame) {
        foreach ($this->prefixes as $prefix) {
            if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     *    Grabs a current stack trace.
     *    @return array        Fulle trace.
     */
    private function captureTrace() {
        if (function_exists('debug_backtrace')) {
            return array_reverse(debug_backtrace());
        }
        return array();
    }
}
?>
